/* ================================================= */
/* parser pour l'analyse syntaxique du code net_list */
/* author Mathieu Barbin , Ocan Sankur               */
/* version samedi 17 novembre 2007                   */
/* ================================================= */

%{
  open Message
  open Inputtools

  let parse_filter_net fct = 
    let f = function
      | Simple s -> s
      | _ -> failwith (Printf.sprintf "Fonction %s, erreur dans les parametres" fct)
    in List.map f

  let parse_filter_decl fct = 
    let f = function
      | Index (VAR p) -> p
      | _ -> failwith  (Printf.sprintf "Fonction %s, erreur dans les parametres" fct)
    in List.map f

  let parse_filter_call fct = 
    let f = function
      | Index e -> e
      | _ -> failwith  (Printf.sprintf "Fonction %s, erreur dans les parametres" fct)
    in List.map f

  let default_main = ref ""

%}

%token SETCPS
%token TAG_INCLUDE
%token DEFINE
%token WITH
%token UNUSED
%token WHERE
%token END
%token TOK_PIPE
%token DEF
%token EXTERNAL
%token INIT
%token ROM
%token RAM
%token TEXT
%token FILE
%token BINARYFILE
%token FOR
%token DO
%token TO
%token IF
%token THEN
%token ELSE
%token LEX_LOG
%token LEX_MOD
%token LEX_ADD
%token LEX_SUB
%token LEX_MULT
%token LEX_DIV
%token LEX_EXP
%token LEX_MIN
%token LEX_MAX
%token LPAREN
%token RPAREN
%token CONDEGAL
%token EGAL
%token NOTEGAL
%token POINT_EXCLAM
%token PPETIT
%token PGRAND
%token SPPETIT
%token SPGRAND
%token LEX_OR
%token LEX_AND
%token POINT_VIRG
%token POINT_INTER
%token DOLLAR
%token VIRG
%token DEUX_POINTS
%token POINTPOINT
%token POINT
%token LACC
%token RACC
%token LCROCHET
%token RCROCHET
%token <int> INT
%token <string> IDENT
// %token <string> IDENTPOINT
%token <string> STRING
%token <string> CODE
%token EOF

// le fichier net_list comprend 5 parties qui sont 

// 0-les fichiers inclus
// 1-les macro #define 
// 2-les déclarations des RAM et ROM
// 3-La déclaration des blocs externes
// 4-une liste de fonctions
// 5-un main par default

// une net_list est donc un quintuplet 
// (define, declaration des memoires, declarations des blocs externes, declaration des fonctions) 

// une declaration de fonction est un constituee 
// d'un nom, d'une liste d'entree, d'une liste de sortie, et d'un corps qui est une liste d'appels imbriques

%type <((Inputtools.include_file list)* (Inputtools.macro_define list) * (Inputtools.declaration_memoire list) * ((string * Inputtools.raw_declaration_bloc_externe) list) * (Inputtools.declaration_generique_fonction list) * string)> net_list
%start net_list

%%

net_list: 
  | include_list macro_define_list declaration_memoire_list declaration_bloc_externe_list declaration_fonction_list   { ($1, $2, $3, $4, $5, !default_main) }
;


point_virg_option:
  | POINT_VIRG { () }
  |            { () }
;

//setCPS:
//  |              { () }
//  | SETCPS INT   { Inputtools.cps := $2 }
//;

// 0 : les include_file

include_list:
  |                            { [] }
  | include_file include_list  { $1::$2 }
;

include_file:
  | TAG_INCLUDE STRING 
      {
        {
          ligne_include = !index_ligne_net_list;
          type_include = CurrentDir $2
        }
      }
  | TAG_INCLUDE SPPETIT IDENT SPGRAND
      {
        {
          ligne_include = !index_ligne_net_list;
          type_include = BebopDir $3
        }
      }
  |  TAG_INCLUDE SPPETIT IDENT POINT IDENT SPGRAND
      {
        {
          ligne_include = !index_ligne_net_list;
          type_include = BebopDir ($3^"."^$5)
        }
      }
;

// 1 : les macro_define

macro_define_item:
  | DEFINE IDENT expr_arith                         
      { 
	{
	  fichier_macro = message#get_net_list;
	  ligne_macro = !index_ligne_net_list; 
	  nom_macro = $2; 
	  corps_macro = DefInt $3
	}
      }
  | DEFINE IDENT LPAREN expr_bool POINT_INTER expr_arith DEUX_POINTS expr_arith RPAREN               
      { 
	{
	  fichier_macro = message#get_net_list;
	  ligne_macro = !index_ligne_net_list; 
	  nom_macro = $2; 
	  corps_macro = DefCondInt ($4, $6, $8)
	}
      }    
  | DEFINE IDENT STRING 
      { 
	{
	  fichier_macro = message#get_net_list;
	  ligne_macro = !index_ligne_net_list;
	  nom_macro = $2;
	  corps_macro = DefString $3
	}
      }
  | DEFINE IDENT LPAREN expr_bool POINT_INTER STRING DEUX_POINTS STRING RPAREN 
      { 
	{
	  fichier_macro = message#get_net_list;
	  ligne_macro = !index_ligne_net_list;
	  nom_macro = $2;
	  corps_macro = DefCondString ($4, $6, $8)
	}
      } 
;

macro_define_list:
  |   { [] }
  | macro_define_item macro_define_list { $1::$2 }
;

// 2 : les declarations des memoires

declaration_memoire_list:
  |                                            { [] }
  | une_memoire declaration_memoire_list       { $1::$2 } 
;

une_memoire:
  | ROM IDENT LPAREN expr_arith VIRG expr_arith RPAREN EGAL text_or_file           
      { 
	{ 
	  fichier_dcl_m = message#get_net_list;
	  ligne_dcl_m = !index_ligne_net_list;
	  type_dcl_m = ROM_decl $2;
	  arite_entree_dcl_m = $4;
	  arite_sortie_dcl_m = $6;
	  description_entree_dcl_m = Some $9 
	}
      }

  | RAM IDENT LPAREN expr_arith VIRG expr_arith RPAREN EGAL text_or_file           
      { 
	{ 
	  fichier_dcl_m = message#get_net_list;
	  ligne_dcl_m = !index_ligne_net_list;
	  type_dcl_m = RAM_decl $2;
	  arite_entree_dcl_m = $4;
	  arite_sortie_dcl_m = $6;
	  description_entree_dcl_m = Some $9 
	}
      }

  | RAM IDENT LPAREN expr_arith VIRG expr_arith RPAREN                             
      { 
	{
	  fichier_dcl_m = message#get_net_list;
	  ligne_dcl_m = !index_ligne_net_list;
	  type_dcl_m = RAM_decl $2;
	  arite_entree_dcl_m = $4;
	  arite_sortie_dcl_m = $6;
	  description_entree_dcl_m = None 
	} 
      }
;

text_or_file:
  | TEXT CODE                                                        { Text $2 }
  | FILE LPAREN STRING RPAREN                                        { File $3 }
  | BINARYFILE LPAREN STRING RPAREN				     { BinaryFile $3 }
;


// 3 - les declarations des blocs externes

declaration_bloc_externe_list:
  |                                                                  { [] }
  | bloc_externe declaration_bloc_externe_list                       { $1::$2 }
;

bloc_externe:
  | EXTERNAL ident_list_option IDENT STRING
      { $3, 
	{
	  raw_attributs = $2;
	  raw_fichier_bloc_ext = message#get_net_list;
	  raw_ligne_bloc_ext = !index_ligne_net_list;
          raw_nom_bloc_ext = $3;
          raw_init_messages_def_method = [];
          raw_command_shell = $4;
	}
      }
  | EXTERNAL ident_list_option IDENT STRING init_message_def_method_list END EXTERNAL POINT_VIRG                       
      { $3,
        {
	  raw_attributs = $2;
	  raw_fichier_bloc_ext = message#get_net_list;
          raw_ligne_bloc_ext = !index_ligne_net_list;
          raw_nom_bloc_ext = $3;
          raw_init_messages_def_method = $5;
          raw_command_shell = $4;
        } 
      }
;

init_message_def_method:
  | INIT STRING point_virg_option      
      { ignore $3; SIMPLE (message#get_net_list, !index_ligne_net_list, INIT_MESSAGE_BLOC $2) }
  | DEF ident_list_option STRING STRING point_virg_option    { ignore $5; SIMPLE (message#get_net_list, !index_ligne_net_list, DEF_METHOD_BLOC ($3, ($2, $4))) }
  | DEF ident_list_option IDENT STRING point_virg_option     { ignore $5; SIMPLE (message#get_net_list, !index_ligne_net_list, DEF_METHOD_BLOC ($3, ($2, $4))) }

  | FOR IDENT EGAL expr_arith TO expr_arith init_message_def_method_list END FOR point_virg_option
      { ignore $10; FOR_LOOP (message#get_net_list, !index_ligne_net_list, $2, $4, $6, $7) }
  | FOR IDENT EGAL expr_arith init_message_def_method_list END FOR point_virg_option
      { ignore $8; FOR_LOOP (message#get_net_list, !index_ligne_net_list, $2, $4, $4, $5) }    
  | IF expr_bool THEN init_message_def_method_list ELSE init_message_def_method_list END IF point_virg_option
      { ignore $9; COND_DECL (message#get_net_list, !index_ligne_net_list, $2, $4, $6) }
  | IF expr_bool THEN init_message_def_method_list END IF point_virg_option
      { ignore $7; COND_DECL (message#get_net_list, !index_ligne_net_list, $2, $4, []) }
  | IF expr_arith THEN init_message_def_method_list ELSE init_message_def_method_list END IF point_virg_option
      { ignore $9; COND_DECL (message#get_net_list, !index_ligne_net_list, CONST $2, $4, $6) }
  | IF expr_arith THEN init_message_def_method_list END IF point_virg_option
      { ignore $7; COND_DECL (message#get_net_list, !index_ligne_net_list, CONST $2, $4, []) }
;

init_message_def_method_list:
  | { [] }
  | init_message_def_method init_message_def_method_list { $1::$2 }
;

// 4 - les declarations de fonctions 
  
declaration_fonction_list:
    EOF                                                              { [] }
  | fonction declaration_fonction_list                               { $1::$2 }  
;

fonction:
  | ident_list_option IDENT variables_list EGAL variables_list unused_list corps_fonction            
      { 
	default_main := $2;
	STANDARD 
	  { 
	    fichier_dcl_f = message#get_net_list;
	    ligne_dcl_f = !index_ligne_net_list;
	    attribut_dcl_f = $1;
	    nom_dcl_f = $2;
	    entrees_dcl_f = $3;
	    sorties_dcl_f = $5;
	    unused_dcl_f = $6;
	    corps_dcl_f = $7
	  }  
      }
  | ident_list_option IDENT indexation_list arguments_fonctionnels_option variables_list EGAL variables_list unused_list corps_fonction
      { PARAMETREE (
	  {
	    dp_params_formels = (parse_filter_decl $2 $3);
	    dp_args_fcts_formels = $4;
	    dp_partial_params = [];
	    dp_partial_args_fcts = [];
	    dp_declaration =
	      { 
		fichier_dcl_f = message#get_net_list;
		ligne_dcl_f = !index_ligne_net_list;
		attribut_dcl_f = $1;
		nom_dcl_f = $2;
		entrees_dcl_f = $5;
		sorties_dcl_f = $7;
		unused_dcl_f = $8;
		corps_dcl_f = $9
	      } 
	  } )
      }
  | ident_list_option IDENT indexation_list variables_list EGAL variables_list unused_list corps_fonction
      { PARAMETREE (
	  {
	    dp_params_formels = (parse_filter_decl $2 $3);
	    dp_args_fcts_formels = [];
	    dp_partial_params = [];
	    dp_partial_args_fcts = [];
	    dp_declaration =
	      { 
		fichier_dcl_f = message#get_net_list;
		ligne_dcl_f = !index_ligne_net_list;
		attribut_dcl_f = $1;
		nom_dcl_f = $2;
		entrees_dcl_f = $4;
		sorties_dcl_f = $6;
		unused_dcl_f = $7;
		corps_dcl_f = $8
	      } 
	  } )
      }
  | ident_list_option IDENT arguments_fonctionnels_option variables_list EGAL variables_list unused_list corps_fonction
      { PARAMETREE (
	  {
	    dp_params_formels = [];
	    dp_args_fcts_formels = $3;
	    dp_partial_params = [];
	    dp_partial_args_fcts = [];
	    dp_declaration =
	      { 
		fichier_dcl_f = message#get_net_list;
		ligne_dcl_f = !index_ligne_net_list;
		attribut_dcl_f = $1;
		nom_dcl_f = $2;
		entrees_dcl_f = $4;
		sorties_dcl_f = $6;
		unused_dcl_f = $7;
		corps_dcl_f = $8
	      } 
	  } )
      }
;

ident_list :
  |           { [] }
  | IDENT     { [$1] }
  | IDENT VIRG ident_list { $1::$3 }
;

ident_list_option :
  |                               { [] }
  | LCROCHET ident_list RCROCHET  { $2 }
;

arguments_fonctionnels_option :
  | SPPETIT ident_list SPGRAND    { $2 }
;

argument_fonctionnel_effectif : 
  | IDENT                         { PASSING_STYLE $1 }
  | STRING                        { CONSTRUCTION $1 }
;

arguments_fonctionnels_effectifs :
  |                                                                      { [] }
  | argument_fonctionnel_effectif                                        { [$1] }
  | argument_fonctionnel_effectif VIRG arguments_fonctionnels_effectifs { $1::$3 }
;

arguments_fonctionnels_effectifs_option :
  |                                                  { [] }
  | SPPETIT arguments_fonctionnels_effectifs SPGRAND { $2 }
;

ident_point_option :
  | IDENT              { $1 }
  | ident_point        { $1 } 
;

ident_point :
  | IDENT POINT IDENT       { $3 } /* en attente : { $1^"."^$3 } */
;

unused_list:
  |                                               { [] }
  | WITH UNUSED EGAL variables_list               { $4 }
;

corps_fonction:
  WHERE liste_noeud END WHERE POINT_VIRG          { $2 }
;

liste_noeud:
  |                                               { [] }
  | un_noeud liste_noeud                          { $1::$2 }
;

un_noeud:
// Raccourcis pour id
  | variables_list EGAL variables_list POINT_VIRG
      { NOEUD (!index_ligne_net_list, BEBOP ("id", [], []), [NET_VARS $3], $1) }

  | variables_list EGAL sucre_gnd_vdd_list POINT_VIRG
      { NOEUD (!index_ligne_net_list, BEBOP ("id", [], []), $3, $1) }

    // Arguments fonctionnels seuls, sans parametres, avec IDENT classique

//  | variables_list EGAL IDENT arguments_fonctionnels_effectifs_option LPAREN imbriq_list RPAREN POINT_VIRG
//      { NOEUD (!index_ligne_net_list, BEBOP ($3, [], $4), $6, $1) }
    
    // argument fonctionnnels seuls, sans parametres, avec IDENT pointé ou classique
      
  | variables_list EGAL ident_point_option arguments_fonctionnels_effectifs_option LPAREN imbriq_list RPAREN POINT_VIRG   
      { NOEUD (!index_ligne_net_list, BEBOP ($3, [], $4), $6, $1) }


    // Sans rien du tout
//  | variables_list EGAL ident_point_option LPAREN imbriq_list RPAREN POINT_VIRG   
//      { NOEUD (!index_ligne_net_list, BEBOP ($3, [], []), $5, $1) }

    // argument fonctionnel avec indexation, avec IDENT classique
      
 | variables_list EGAL IDENT indexation_list arguments_fonctionnels_effectifs_option LPAREN imbriq_list RPAREN POINT_VIRG
    { NOEUD (!index_ligne_net_list, BEBOP ($3, (parse_filter_call $3 $4), $5), $7, $1) }

    // argument fonctionnel avec indexation, avec IDENT pointé

  | variables_list EGAL ident_point indexation_list arguments_fonctionnels_effectifs_option LPAREN imbriq_list RPAREN POINT_VIRG
      { NOEUD (!index_ligne_net_list, BEBOP ($3, (parse_filter_call $3 $4), $5), $7, $1) }
    
    // Indexation seule, sans argument fonctionnel

//  | variables_list EGAL ident_point indexation_list LPAREN imbriq_list RPAREN POINT_VIRG
  //    { NOEUD (!index_ligne_net_list, BEBOP ($3, (parse_filter_call $3 $4), []), $6, $1) }
  


 // RESTE : PIPE, EXTERNAL
  
  | variables_list EGAL TOK_PIPE LPAREN STRING RPAREN POINT_VIRG
      { NOEUD (!index_ligne_net_list, PIPE ($5, Infere), [], $1) } 

  | variables_list EGAL TOK_PIPE LPAREN STRING VIRG imbriq_list RPAREN POINT_VIRG
      { NOEUD (!index_ligne_net_list, PIPE ($5, Infere), $7, $1 ) }

  | variables_list EGAL DOLLAR IDENT LPAREN string_list_virg imbriq_list RPAREN POINT_VIRG
      { NOEUD (!index_ligne_net_list, EXTERNAL_BLOC ($4, None, $6, Infere), $7, $1) }

  | variables_list EGAL DOLLAR IDENT POINT IDENT LPAREN string_list_virg imbriq_list RPAREN POINT_VIRG
      { NOEUD (!index_ligne_net_list, EXTERNAL_BLOC ($4, Some (ref $6), $8, Infere), $9, $1) }

  | variables_list EGAL DOLLAR IDENT POINT STRING LPAREN string_list_virg imbriq_list RPAREN POINT_VIRG
      { NOEUD (!index_ligne_net_list, EXTERNAL_BLOC ($4, Some (ref $6), $8, Infere), $9, $1) }

  | DOLLAR IDENT LPAREN string_list_virg imbriq_list RPAREN POINT_VIRG
      { NOEUD (!index_ligne_net_list, EXTERNAL_BLOC ($2, None, $4, Infere), $5, []) }
      
  | DOLLAR IDENT POINT IDENT LPAREN string_list_virg imbriq_list RPAREN POINT_VIRG
      { NOEUD (!index_ligne_net_list, EXTERNAL_BLOC ($2, Some (ref $4), $6, Infere), $7, []) }

  | DOLLAR IDENT POINT STRING LPAREN string_list_virg imbriq_list RPAREN POINT_VIRG
      { NOEUD (!index_ligne_net_list, EXTERNAL_BLOC ($2, Some (ref $4), $6, Infere), $7, []) }

  | FOR IDENT EGAL expr_arith TO expr_arith liste_noeud END FOR POINT_VIRG        
      { BOUCLE_FOR (!index_ligne_net_list, $2, $4, $6, $7) }
      
  | FOR IDENT EGAL expr_arith liste_noeud END FOR POINT_VIRG        
      { BOUCLE_FOR (!index_ligne_net_list, $2, $4, $4, $5) }

  | IF expr_bool THEN liste_noeud ELSE liste_noeud END IF POINT_VIRG
      { NOEUD_COND (!index_ligne_net_list, $2, $4, $6) }

  | IF expr_bool THEN liste_noeud END IF POINT_VIRG
      { NOEUD_COND (!index_ligne_net_list, $2, $4, []) }
  
  | IF expr_arith THEN liste_noeud ELSE liste_noeud END IF POINT_VIRG
      { NOEUD_COND (!index_ligne_net_list, CONST $2, $4, $6) }
      
  | IF expr_arith THEN liste_noeud END IF POINT_VIRG
      { NOEUD_COND (!index_ligne_net_list, CONST $2, $4, []) }
;

string_list_virg :
  |                              { [] }
  | STRING                       { [$1] }
  | STRING VIRG string_list_virg { $1::$3 }
; 

variables_list:
    LPAREN arguments RPAREN                            { $2 }
  | arguments                                          { $1 }
; 

arguments:
  |                                                    { [] }
  | argument                                           { [$1] }
  | argument VIRG arguments                            { $1::$3 }
;
 
argument:
  | IDENT                                              { Simple $1 }
  | IDENT indexation_list                              { Vecteur (!index_ligne_net_list,
								  $1,$2) }
;

indexation_list:
  | indexation                                         { [$1] }
  | indexation indexation_list                         { $1::$2 }
;

indexation:
  | DEUX_POINTS LCROCHET expr_arith RCROCHET           { SegmentInit $3 }
  | LCROCHET expr_arith POINTPOINT expr_arith RCROCHET { Intervalle ($2, $4) }
  | LCROCHET expr_arith RCROCHET                       { Index $2 }
;

imbriq_list:
  |                                                    { [] }
  | imbriq                                             { [$1] }
  | imbriq VIRG imbriq_list                            { $1::$3 }
;

// Attention, dans un imbriq, on contraint l'utilisateur à preciser 
// l'arite sortante de ces pipes.

imbriq:
  | argument                                                                     { NET_VARS [$1] }
  | TOK_PIPE LPAREN STRING RPAREN 
      { Message.message#pipe_imbrique_arite_probleme message#get_net_list (!index_ligne_net_list) $3; failwith "w-friendly" }
  | TOK_PIPE LPAREN STRING VIRG imbriq_list RPAREN 
      { Message.message#pipe_imbrique_arite_probleme message#get_net_list (!index_ligne_net_list) $3; failwith "w-friendly" }    

  | DOLLAR IDENT LPAREN imbriq_list RPAREN
      { Message.message#external_imbrique_arite_probleme message#get_net_list (!index_ligne_net_list) $2; failwith "w-friendly" }
  | DOLLAR IDENT POINT IDENT LPAREN imbriq_list RPAREN
      { Message.message#external_imbrique_arite_probleme message#get_net_list (!index_ligne_net_list) $2; failwith "w-friendly" }
  | DOLLAR IDENT POINT STRING LPAREN imbriq_list RPAREN
      { Message.message#external_imbrique_arite_probleme message#get_net_list (!index_ligne_net_list) $2; failwith "w-friendly" }

  | TOK_PIPE LCROCHET expr_arith RCROCHET LPAREN STRING RPAREN                       { IMB (!index_ligne_net_list, PIPE ($6, (Calcul $3)), []) }
  | TOK_PIPE LCROCHET expr_arith RCROCHET LPAREN STRING VIRG imbriq_list RPAREN      { IMB (!index_ligne_net_list, PIPE ($6, (Calcul $3)), $8) }
  | DOLLAR IDENT LCROCHET expr_arith RCROCHET LPAREN string_list_virg imbriq_list RPAREN              { IMB (!index_ligne_net_list, EXTERNAL_BLOC ($2, None, $7, (Calcul $4)), $8) }
  | DOLLAR IDENT POINT IDENT LCROCHET expr_arith RCROCHET LPAREN string_list_virg imbriq_list RPAREN  { IMB (!index_ligne_net_list, EXTERNAL_BLOC ($2, Some (ref $4), $9, (Calcul $6)), $10) }
  | DOLLAR IDENT POINT STRING LCROCHET expr_arith RCROCHET LPAREN string_list_virg imbriq_list RPAREN { IMB (!index_ligne_net_list, EXTERNAL_BLOC ($2, Some (ref $4), $9, (Calcul $6)), $10) }
  | sucre_gnd_vdd { $1 }

  | ident_point_option arguments_fonctionnels_effectifs_option LPAREN imbriq_list RPAREN          
      { IMB (!index_ligne_net_list, BEBOP ($1, [], $2), $4) }
  | IDENT indexation_list arguments_fonctionnels_effectifs_option LPAREN imbriq_list RPAREN 
      { IMB (!index_ligne_net_list, BEBOP ($1, (parse_filter_call $1 $2), $3), $5) }
  | ident_point indexation_list arguments_fonctionnels_effectifs_option LPAREN imbriq_list RPAREN 
      { IMB (!index_ligne_net_list, BEBOP ($1, (parse_filter_call $1 $2), $3), $5) } 
;


sucre_gnd_vdd:
  | INT  { match $1 with
	   | 0 -> IMB (!index_ligne_net_list, BEBOP ("gnd", [], []), []) 
	   | 1 -> IMB (!index_ligne_net_list, BEBOP ("vdd", [], []), [])
	   | _ -> raise Parsing.Parse_error
	 }
  | LEX_SUB INT // Sucre syntaxique pour vdd (-1)
      { match $2 with
	| 1 -> IMB (!index_ligne_net_list, BEBOP ("vdd", [], []), [])
	| _ -> raise Parsing.Parse_error
      }  
;

sucre_gnd_vdd_list:
  | sucre_gnd_vdd                                      { [$1] }
  | sucre_gnd_vdd VIRG sucre_gnd_vdd_list              { $1::$3 }
;

// LES EXPRESSIONS ARITHMETIQUES 

expr_arith:
  | expr_arith LEX_ADD expr_arith_close    { ADD ($1, $3) }
  | expr_arith LEX_SUB expr_arith_close    { SUB ($1, $3) }
  | LEX_SUB expr_arith_close               { SUB (CST 0, $2) }
  | expr_arith_close                       { $1 }
;

expr_arith_close:
  | expr_arith_close LEX_DIV expr_prio     { DIV ($1, $3) }
  | expr_arith_close LEX_MULT expr_prio    { MULT ($1, $3) }
  | expr_arith_close LEX_MOD expr_prio     { MOD ($1, $3) }
  | expr_prio                              { $1 }
;

expr_prio:
  | expr_prio LEX_EXP expr_terminale       { EXP ($1, $3) }
  | LEX_LOG expr_terminale                 { LOG $2 }
  | expr_terminale                         { $1 }
                               
expr_terminale:
  | INT                                                  { CST $1 }
  | IDENT                                                { VAR $1 }
  | LPAREN expr_arith RPAREN                             { $2 }
  | LEX_MAX LPAREN expr_arith VIRG expr_arith RPAREN     { MAX ($3, $5) }
  | LEX_MIN LPAREN expr_arith VIRG expr_arith RPAREN     { MIN ($3, $5) } 
;

// LES EXPRESSIONS BOOLEENNES

expr_bool:
  | expr_bool LEX_OR expr_bool_close                     { COND_OR ($1, $3) }
  | expr_bool_close                                      { $1 }
;

expr_bool_close:
  | expr_bool_close LEX_AND expr_bool_terminale          { COND_AND ($1, $3) }
//  | POINT_EXCLAM expr_bool_terminale                     { COND_NEG ($2) }
  | expr_bool_terminale                                  { $1 }
;
  
expr_bool_terminale:
  |  expr_arith EGAL expr_arith                          { COND_EQ ($1, $3) }
  |  expr_arith CONDEGAL expr_arith                      { COND_EQ ($1, $3) }
  |  expr_arith NOTEGAL expr_arith                       { COND_NEQ ($1, $3) }
  |  expr_arith PPETIT expr_arith                        { COND_PP ($1, $3) }
  |  expr_arith PGRAND expr_arith                        { COND_PG ($1, $3) }
  |  expr_arith SPPETIT expr_arith                       { COND_SPP ($1, $3) }
  |  expr_arith SPGRAND expr_arith                       { COND_SPG ($1, $3) }
  |  POINT_EXCLAM expr_arith                             { COND_NEG (CONST $2) }
  |  POINT_EXCLAM LPAREN expr_bool RPAREN                { COND_NEG $3 }
  |  LPAREN expr_bool RPAREN                             { $2 }
;

